//=============================================================================
/**
 * @file	fld_res_obj.c
 * @brief	フィールドのリソース・ＯＢＪをつなぐマネージャ
 * @author	Nozomu Saito
 *
 */
//=============================================================================
#include "common.h"
#include "fld_res_obj.h"

typedef    u8	OBJ_IDX_SIZE;
#define NOT_ENTRY_OBJ	(0xff)

typedef struct F_RES_OBJ_MNG_tag
{
	OBJ_IDX_SIZE *TblData;
	NNSG3dResFileHeader	**ResTable;
	F_OBJ_DATA	*ObjectDataTbl;
//	NNSG3dResMdl* 	objectmodel;				//モデリングデータポインタ
	F_OBJ_DATA	**ObjDatStack;
	int StackPt;
	u32 ResNum;
	u32 ObjNum;
}F_RES_OBJ_MNG;

static  F_OBJ_DATA	* InitRenderObj(F_RES_OBJ_MNG_PTR pMngPtr, NNSG3dResFileHeader** inRes, const int inResID);

//==============================================================================
/**
 * マネージャ初期化
 *
 * @param   inHeapID	ヒープＩＤ
 * @param	inResNum	リソース数
 * @param	inObjNum	オブジェクト数
 * @param	inRes		リソースへのポインタのポインタ
 *
 * @retval  ptr			マネージャポインタ
 */
//==============================================================================
F_RES_OBJ_MNG_PTR F_RES_OBJ_InitManager(	const int inHeapID,
										const int inResNum,
										const int inObjNum,
										NNSG3dResFileHeader **inRes)
{
	int i;
	int size;
	F_RES_OBJ_MNG_PTR ptr;
	ptr = sys_AllocMemory(inHeapID, sizeof(F_RES_OBJ_MNG));
	ptr->StackPt = 0;
	ptr->ResNum = inResNum;
	ptr->ObjNum = inObjNum;
	ptr->ResTable = inRes;
	ptr->TblData = sys_AllocMemory(inHeapID, sizeof(OBJ_IDX_SIZE)*inResNum);
	for( i=0; i<inResNum; i++ )
	{
		ptr->TblData[i] = NOT_ENTRY_OBJ;
	}

	size = sizeof(F_OBJ_DATA)*inObjNum;
	ptr->ObjectDataTbl = sys_AllocMemory(inHeapID,size);
	MI_CpuClearFast(ptr->ObjectDataTbl,size);

	ptr->ObjDatStack = (F_OBJ_DATA	**)sys_AllocMemory(inHeapID,sizeof(int)*inObjNum);
	for( i=0; i<inObjNum; i++ )
	{
		ptr->ObjDatStack[i] = &(ptr->ObjectDataTbl[i]);
	}

	return ptr;

}

//==============================================================================
/**
 * 終了
 *
 * @param   pMngPtr	マネージャポインタ
 *
 * @retval  none
 */
//==============================================================================
void F_RES_OBJ_End(	F_RES_OBJ_MNG_PTR pMngPtr )
{
	sys_FreeMemoryEz( pMngPtr->TblData );
	sys_FreeMemoryEz( pMngPtr->ObjectDataTbl );
	sys_FreeMemoryEz( pMngPtr->ObjDatStack );
	sys_FreeMemoryEz( pMngPtr );
}


//==============================================================================
/**
 * リソースを指定して、レンダーOBJの初期化
 *
 * @param   pMngPtr		マネージャポインタ
 * @param	inResID		リソースＩＤ
 *
 * @retval  F_OBJ_DATA	OBJデータポインタ
 */
//==============================================================================
F_OBJ_DATA	*F_RES_OBJ_EntryRes(F_RES_OBJ_MNG_PTR pMngPtr, const int inResID)
{
	NNSG3dResFileHeader	*res;
	pMngPtr->TblData[inResID] = pMngPtr->StackPt;
	//管理マネージャからあいているところを取得
	res = pMngPtr->ResTable[inResID];
	return InitRenderObj(pMngPtr, &res, inResID);
}

//==============================================================================
/**
 * レンダーOBJのエントリ解除
 *
 * @param   pMngPtr		マネージャポインタ
 * @param	inObjData	OBJデータポインタ
 *
 * @retval  none
 */
//==============================================================================
void F_RES_OBJ_ClearEntry(F_RES_OBJ_MNG_PTR pMngPtr, F_OBJ_DATA	*inObjData)
{
	pMngPtr->StackPt--;
	pMngPtr->ObjDatStack[pMngPtr->StackPt] = inObjData;
///	OS_Printf("エントリをクリア:%d__stack=%d\n",inObjData->ResID,pMngPtr->StackPt);
}

//==============================================================================
/**
 * リソースIDをキーにして、OBJデータへのポインタ取得
 *
 * @param   pMngPtr		マネージャポインタ
 * @param	inResID		リソースＩＤ
 *
 * @retval  F_OBJ_DATA	OBJデータポインタ
 */
//==============================================================================
F_OBJ_DATA	*F_RES_OBJ_GetRenderObjPtr(F_RES_OBJ_MNG_PTR pMngPtr, const int inResID)
{
	int idx;
	idx = pMngPtr->TblData[inResID];
	if (idx != NOT_ENTRY_OBJ){
		return pMngPtr->ObjDatStack[idx];
	}

	return NULL;
}

//==============================================================================
/**
 * リソースIDをキーにして、OBJデータを作成してポインタを取得
 *
 * @param   pMngPtr		マネージャポインタ
 * @param	inResID		リソースＩＤ
 *
 * @retval  F_OBJ_DATA	OBJデータポインタ
 */
//==============================================================================
F_OBJ_DATA	*F_RES_OBJ_CreateObjPtr(F_RES_OBJ_MNG_PTR pMngPtr, const int inResID)
{
	F_OBJ_DATA	*obj;
	NNSG3dResFileHeader	*res;
	//管理マネージャからあいているところを取得
	res = pMngPtr->ResTable[inResID];
	obj = InitRenderObj(pMngPtr, &res, inResID);
///	OS_Printf("エントリしてないので作成:%d__stack=%d\n",inResID, pMngPtr->StackPt);
	return obj;
}

//==============================================================================
/**
 * リソースIDをキーにして、レンダーOBJを割り当てる。
 * あらかじめレンダーOBJをエントリーしてない場合は、エントリーして割り当てる。
 *
 * @param   pMngPtr		マネージャポインタ
 * @param	inResID		リソースＩＤ
 *
 * @retval  F_OBJ_DATA	OBJデータポインタ
 */
//==============================================================================
F_OBJ_DATA	*F_RES_OBJ_AssignRenderObjPtr(F_RES_OBJ_MNG_PTR pMngPtr, const int inResID)
{
	if ( F_RES_OBJ_IsEntry(pMngPtr, inResID) ){
		return F_RES_OBJ_GetRenderObjPtr(pMngPtr, inResID);
	}else{
		return F_RES_OBJ_CreateObjPtr(pMngPtr, inResID);
	}
}

//==============================================================================
/**
 * レンダーOBJを割りてを解除する。
 * ただし、解除対象は、重複エントリ可能OBJに限る。
 * それ以外の、割り当ては解除は処理をスルーする。
 *
 * @param   pMngPtr		マネージャポインタ
 * @param	inObjData	OBJデータポインタ
 *
 * @retval  BOOL	TRUE:クリア成功　FALSE:クリア失敗
 */
//==============================================================================
BOOL	F_RES_OBJ_ReturnRenderObjPtr(F_RES_OBJ_MNG_PTR pMngPtr, F_OBJ_DATA	*inObjData)
{
	if (inObjData == NULL){
		return FALSE;
	}
	if ( !F_RES_OBJ_IsEntry(pMngPtr, inObjData->ResID) ){
		F_RES_OBJ_ClearEntry(pMngPtr, inObjData);
		return TRUE;
	}
	return FALSE;
}

//==============================================================================
/**
 * 重複エントリチェック
 *
 * @param   pMngPtr		マネージャポインタ
 * @param	inResID		リソースＩＤ
 *
 * @retval  BOOL	TRUE:エントリ済み	FALSE:未エントリ
 */
//==============================================================================
BOOL F_RES_OBJ_IsEntry(F_RES_OBJ_MNG_PTR pMngPtr, const int inResID)
{
	int idx;
	idx = pMngPtr->TblData[inResID];
	if (idx != NOT_ENTRY_OBJ){
		return TRUE;
	}else{
		return FALSE;
	}
}

//==============================================================================
/**
 * リソースのエントリーチェック
 *
 * @param   pMngPtr		マネージャポインタ
 * @param	inResID		リソースＩＤ
 *
 * @retval  TRUE:登録済み	FALSE:未登録
 */
//==============================================================================
BOOL F_RES_OBJ_CheckResourceEntry(F_RES_OBJ_MNG_PTR pMngPtr, const int inResID)
{
	if ( pMngPtr->ResTable[inResID] == NULL ){
		return FALSE;
	}else{
		return TRUE;
	}
}

//==============================================================================
/**
 * リソースを指定して、レンダーOBJの初期化
 *
 * @param   pMngPtr		マネージャポインタ
 * @param	inRes		リソースへのポインタのポインタ
 * @param	inResID		リソースＩＤ
 *
 * @retval  F_OBJ_DATA	OBJデータポインタ
 */
//==============================================================================
static F_OBJ_DATA	*InitRenderObj(F_RES_OBJ_MNG_PTR pMngPtr, NNSG3dResFileHeader** inRes, const int inResID)
{
	F_OBJ_DATA	*obj;
	pMngPtr->ObjDatStack[pMngPtr->StackPt]->ResMdl =
		NNS_G3dGetMdlByIdx(NNS_G3dGetMdlSet(*inRes), 0);
	NNS_G3dRenderObjInit(	&(pMngPtr->ObjDatStack[pMngPtr->StackPt]->RenderObj),
							pMngPtr->ObjDatStack[pMngPtr->StackPt]->ResMdl	);
	obj = pMngPtr->ObjDatStack[pMngPtr->StackPt];
	pMngPtr->StackPt++;
	obj->ResID = inResID;
	return obj;
}
